package com.river.springbootdemo.thinkingjava.containers;

import java.util.List;

public class Tester<C> {
    public static int fieldWidth = 8;
    public static TestParam[] defaultParams = TestParam.array(10, 5000, 100, 5000, 1000, 5000, 10000, 5000);
    protected C container;
    private String headline = "";
    private List<Test<C>> tests;
    private static int sizeWidth = 5;
    private static String sizeField="%"+sizeWidth+"s";

    //override this to modify pre-test initialization
    protected C initialize(int size) {
        return container;
    }

    private static String stringField() {
        return "%" + fieldWidth + "s";
    }

    private static String numberField() {
        return "%" + fieldWidth + "d";
    }

    private TestParam[] paramList = defaultParams;

    public Tester(C container, List<Test<C>> tests) {
        this.container = container;
        this.tests = tests;
        if (container != null) {
            headline = container.getClass().getSimpleName();
        }
    }

    public void setHeadline(String headline) {
        this.headline = headline;
    }

    //Generic methods for convenience
    public static <C> void run(C cntnr, List<Test<C>> tests) {
        new Tester<C>(cntnr, tests).timedTest();
    }

    private void displayHeader() {
        //calculate width and pad with ‘-’:
        int width = fieldWidth * tests.size() +sizeWidth;
        int dashLength = width-headline.length()-1;
        StringBuilder head = new StringBuilder(width);
        for (int i=0;i<dashLength/2;i++){
            head.append("-");
        }
        head.append(' ');
        head.append(headline);
        head.append(' ');
        for (int i=0;i<dashLength/2;i++){
            head.append("-");
        }
        System.out.println(head);
        //print column headers:
        System.out.format(stringField(),"size");
        for (Test test:tests){
            System.out.format(stringField(),test.name);
        }
        System.out.println();
    }

    //Run the tests for this container
    public void timedTest() {
        displayHeader();
        for (TestParam param:paramList){
            System.out.format(sizeField,param.size);
            for (Test<C> test:tests){
                C kontainer = initialize(param.size);
                long start = System.nanoTime();
                //Call the override method
                int reps = test.test(kontainer,param);
                long dutation = System.nanoTime()-start;
                long timePerRep = dutation/reps;//Nanoseconds
                System.out.format(numberField(),timePerRep);
            }
            System.out.println();
        }
    }
}
